console.info("迭代器教学");

// 迭代器主要用来遍历具备集合属性的对象，所谓集合属性就是指上面几种类型
// Iterator 的遍历过程是这样的。
//（1）创建一个指针对象，指向当前数据结构的起始位置。也就是说，遍历器对象本质上，就是一个指针对象。
//（2）第一次调用指针对象的next方法，可以将指针指向数据结构的第一个成员。
//（3）第二次调用指针对象的next方法，指针就指向数据结构的第二个成员。
//（4）不断调用指针对象的next方法，直到它指向数据结构的结束位置。
//每一次调用next方法，都会返回数据结构的当前成员的信息。具体来说，就是返回一个包含value和done两个属性的对象。其中，value属性是当前成员的值，done属性是一个布尔值，表示遍历是否结束。

// Iterator 只是把接口规格加到数据结构之上，所以，遍历器与它所遍历的那个数据结构，实际上是分开的

// for...of循环会自动寻找iterator接口并使用
// 只要有iterator属性的对象，就可以被for ...of

// 简单数据for ... of
/**
 * 打印
 * e=1
 * e=3
 * e=4
 * e=6
 */
let simpleArray = [1, 3, 4, 6];
for (let e of simpleArray) {
    console.log("e=%s", e);
}

/**
 * 原生具备 Iterator 接口的数据结构如下。
 * Array
 * Map
 * Set
 * String
 * TypedArray有类型的数组
 * 函数的 arguments 对象
 * NodeList 对象
 */

// 使用map这种数据结构，迭代器遍历出来的是一个数组，第0位是key，第1位是value
// e=[ 'a', 100 ]
// e=[ 'b', 3.25 ]
let tmpMap = new Map();
tmpMap.set("a", 100);
tmpMap.set("b", 3.25);
for (let e of tmpMap) {
    console.log(e);
}

// 使用set数据结构
// e=a
// e=b
let tmpSet = new Set();
tmpSet.add("a");
tmpSet.add("b");
for (let e of tmpSet) {
    console.log("e=%s", e);
}

// 使用string类型数据
// c=你
// c=好
let tmpString = "你好";
for (let e of tmpString) {
    console.log("c=%s", e);
}

// 函数的arguments
// arg=1
// arg=test
// arg={ a: 100, b: 20 }
let tmpFunc = function () {
    for (let e of arguments) {
        console.log("arg=%s", e);
    }
}
tmpFunc(1, "test", { a: 100, b: 20 });

// 如果我们不想用for of来迭代，而是自己控制对象的迭代器函数，那么应该使用Symbol.iterator来获取

// 获取简单数组迭代器
let itor = simpleArray[Symbol.iterator]();
console.log(itor.next());//{ value: 1, done: false }
console.log(itor.next());//{ value: 3, done: false }

// 获取字符串迭代器
itor = tmpString[Symbol.iterator]();
console.log(itor.next());//{ value: '你', done: false }
console.log(itor.next());//{ value: '好', done: false }

// 普通对象只能for in不能for of是因为默认的引擎不知道如何遍历对象的顺序，因此需要自己自定义
// 自定义的方式如下所示：
let simpleObject = {
    "name": "brook",
    "age": 40,
    "sex": true,
    [Symbol.iterator]: function () {
        let i = 0;
        let self = this;
        return {
            next: function() {
                if(i==0){
                    i++;
                    return { "done": false, value: self.name }
                }
                if(i==1){
                    i++;
                    return { "done": false, value: self.age }
                }
                if(i==2){
                    i++;
                    return { "done": false, value: self.sex }
                }
                return {"done":true,value:null}
            },
            "return": function(){
                console.log("return called");
            }
        }
    }
};

// 上面迭代器return方法会在抛异常或者break中断的时候被调用
for (let x of simpleObject) {
    console.log("x=%s", x);
}